﻿using System;
using System.Collections.Generic;
using System.Reflection;
using DepIC;

namespace TeF.Runner.Services
{
    [Serializable]
    internal sealed class TestRunHelper : MarshalByRefObject
    {
        private Assembly _testAssembly;
        private readonly IDictionary<string, object> _instatces = new Dictionary<string, object>();

        private IReadOnlyContainer Container
        {
            get { return IoCHelper.Container; }
        }
        
        public void LoadAssembly(string testAssemblyPath)
        {
            if (string.IsNullOrWhiteSpace(testAssemblyPath))
                throw new ArgumentException("testAssemblyPath");

            _testAssembly = Container.Get<ITestAssemblyLoader>().Load(testAssemblyPath);
        }
        
        public void CreateInstanceOfType(string typeFullName)
        {
            if (string.IsNullOrWhiteSpace(typeFullName))
                throw new ArgumentException("typeFullName");

            if (_testAssembly == null)
                throw new TestRunnerException("Assembly is not loaded.");

            if (_instatces.ContainsKey(typeFullName))
                return;

            var type = _testAssembly.GetType(typeFullName, true);

            var instance = Activator.CreateInstance(type);
            _instatces.Add(typeFullName, instance);
        }

        public void DistroyInstanceOfType(string typeFullName)
        {
            if (string.IsNullOrWhiteSpace(typeFullName))
                throw new ArgumentException("typeFullName");

            if (_testAssembly == null)
                throw new TestRunnerException("Assembly is not loaded.");

            if (!_instatces.ContainsKey(typeFullName))
                return;

            _instatces.Remove(typeFullName);
        }

        public void ExecuteMethodOfType(string typeFullName, string methodName)
        {
            if (string.IsNullOrWhiteSpace(typeFullName))
                throw new ArgumentException("typeFullName");

            if (string.IsNullOrWhiteSpace(methodName))
                throw new ArgumentException("methodName");

            if (_testAssembly == null)
                throw new TestRunnerException("Assembly is not loaded.");

            if (!_instatces.ContainsKey(typeFullName))
                throw new TestRunnerException(@"Type ""{0}"" is not created.", typeFullName);

            var instance = _instatces[typeFullName];
            var type = instance.GetType();

            var method = type.GetMethod(methodName);
            if (method == null)
                throw new TestRunnerException(@"Method ""{0}"" of type ""{1}"" is not found.", methodName, typeFullName);

            try
            {
                method.Invoke(instance, null);
            }
            catch (Exception ex)
            {
                throw new TestRunException(ex, @"Method ""{0}"" of type ""{1}"" is failed.", methodName, typeFullName);
            }
        }
    }
}
